package com.kehutong.common.interceptor;

import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import org.coraframework.authz.AthInterceptor;
import org.coraframework.authz.SubjectUtil;
import org.coraframework.authz.exception.AuthenticationException;
import org.coraframework.authz.exception.NotPermissionException;
import org.coraframework.authz.exception.UnloginException;
import org.coraframework.authz.util.CookieUtils;
import org.coraframework.inject.Inject;
import org.coraframework.inject.Singleton;
import org.coraframework.json.JSONObject;
import org.coraframework.logger.Logger;
import org.coraframework.logger.LoggerFactory;
import org.coraframework.orm.jdbc.JdbcSession;
import org.coraframework.orm.jdbc.connection.ThreadLocalCache;
import org.coraframework.orm.jdbc.execute.DataFilter;
import org.coraframework.orm.util.FilterBean;
import org.coraframework.util.Objects;

import com.kehutong.common.DoveClient;
import com.kehutong.common.entity.Root;
import com.kehutong.common.util.Token;

/**
 * 权限拦截器
 * @author liuzhen
 *
 * email liuxing521a@kuwan123.com
 * time  2018年4月21日下午2:26:20
 */
@Singleton
public class PermissionInterceptor implements AthInterceptor {
	
	private static final Logger logger = LoggerFactory.getLogger(PermissionInterceptor.class);
	
	@Inject
	private DoveClient doveClient;
	@Inject
	private JdbcSession jdbcSession;

	@Override
	public boolean beforeHandle(HttpServletRequest req, Object handler) {
		try {
			if (isLogin(req)) {
				return true;
			}
			
			Token token =obtainToken(req);
			if (handler == null) {
				return true;
			}
			
			if (Objects.isNull(token)) {
				throw new UnloginException();
			}

			// 检查权限
			if (!(handler instanceof Set)) {
				return false;
			}
			
			if (Root.isRoot(token.getUuid())) {//超级管理员
				return true;
			}

			@SuppressWarnings("unchecked")
			Set<String> permission = (Set<String>)handler;
			if (!checkPermission(token, permission) /*|| !checkRole(method, userId)*/) {
				throw new NotPermissionException();
			}
			
			setDataFilter(token, permission);
			return true;
		} catch (NotPermissionException|UnloginException e) {
			throw e;
		} catch (Exception e) {
			throw new AuthenticationException(e.getMessage(), e);
		}
	}

	@Override
	public boolean afterHandle(HttpServletRequest req, Object handler) {
		ThreadLocalCache.current().clear();
		return false;
	}

	/**
	 * 检查权限
	 *
	 * @param permissions 权限列表
	 * @return true:有权限, false:无权限
	 */
	private boolean checkPermission(Token token, Set<String> permissions) {
		if (Objects.isEmpty(permissions)) {
			return true;
		}
		
		Set<String> userPermissions = token.getPermissions();
		if (Objects.isEmpty(userPermissions)) {
			return false;
		}
		
		for (String permission : permissions) {
			if (userPermissions.contains(permission)) {
				return true;
			}
		}
		
		return false;
	}
	
	// 获取token
	private Token obtainToken(HttpServletRequest req) throws Exception {
		/*begin 企业服务之间token*/
		String companyNo = req.getHeader("companyNo");
		if (Objects.nonEmpty(companyNo)) {
			setCorpDB(companyNo);
			Token token=Token.create().setCompanyNo(companyNo);
			token.setReq(req);
			req.setAttribute("token", token);
			return token;
		}/*end*/
		
		/*begin 用户token*/
		Token token = getUserToken(req);
		if (Objects.nonNull(token)) {
			setCorpDB(token.getCompanyNo());
			token.setReq(req);
			req.setAttribute("token", token);
			return token;
		}/*end*/
		
		return null;
	}
	
	private Token getUserToken(HttpServletRequest req) throws Exception {
		String cookieId = CookieUtils.getCookieValue(req);
		if (Objects.isEmpty(cookieId)) {
			return null;
		}
		
		JSONObject rs = doveClient.post("/kht-bin/session/service/get", http->http.addParam("sessionId", cookieId));
		if (rs.getInteger("code") != 200) {
			logger.error("getToken fail: {}", rs.getString("message"));
			return null;
		}
	
		return Token.fromJSON(rs.getJSONObject("data"));
	}
	
	
	private boolean isLogin(HttpServletRequest request) throws Exception {
		String requestRri = request.getRequestURI();
		String uriPrefix = request.getContextPath();
		if (requestRri.startsWith(uriPrefix) && requestRri.endsWith("/login")){
			setCorpDB(null);
			return true;
		}
		
		return false;
	}
	
	private void setCorpDB(String companyNo) {
		ThreadLocalCache.current().setCorpId(companyNo);
	}
	
	private void setDataFilter(Token token, Set<String> permissions) {
		DataFilter filter = getFilter(token, permissions);
		if (Objects.nonNull(filter)) {
			FilterBean fbean = FilterBean.create()
					.setDataFilter(filter)
					.setOfficeList(token.getDepartments());
			
			ThreadLocalCache.current().setfBean(fbean);
		}
		
	}
	
	private DataFilter getFilter(Token token, Set<String> permissions) {
		Map<String, DataFilter> filterMap = SubjectUtil.getSubject().getAttr("permissions");
		if (filterMap != null) {
			for (String permission : permissions) {
				return filterMap.get(permission);
			}
		}

		return null;
	}
}